package edu.rpi.tw.escience.stargazer.server;

import edu.rpi.tw.escience.stargazer.math.Math;
import edu.rpi.tw.escience.stargazer.onto.Star;
import org.apache.log4j.PropertyConfigurator;
import org.openrdf.model.URI;
import org.openrdf.model.impl.URIImpl;
import org.openrdf.model.vocabulary.RDF;
import org.openrdf.repository.Repository;
import org.openrdf.repository.RepositoryConnection;
import org.openrdf.repository.RepositoryException;
import org.openrdf.repository.sail.SailRepository;
import org.openrdf.rio.RDFFormat;
import org.openrdf.rio.RDFParseException;
import org.openrdf.sail.inferencer.fc.ForwardChainingRDFSInferencer;
import org.openrdf.sail.memory.MemoryStore;

import javax.xml.namespace.QName;
import java.io.IOException;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;

/*
 * Java5+ Class, showing how to run Java5 server side code.. and Java1.4 GWT Client code simultaneously in GWT-Maven
 */
public class StarGazer {
    private static final String LOG4J_PROPERTIES = "log4j.properties";

    static {
        PropertyConfigurator.configure(
                StarGazer.class.getResource(LOG4J_PROPERTIES));
    }

    private static StarGazer singleton;
    private StarGazerContext context;

    public static final String NS = "http://tw.rpi.edu/2008/11/stargazer#";

    public static final URI
            // Note: this is only a partial list of classes.
            CELESTIALOBJECT = new URIImpl(NS + "CelestialObject"),
            STAR = new URIImpl(NS + "Star");

    private static final String BASE_URI = "http://example.org/ns#";

    public static String toStarGazerURI(final URI localURI) {
        return NS + localURI.getLocalName();
    }

    public static StarGazer getInstance() throws SimpleException {        
        if (null == singleton) {
            singleton = new StarGazer();
        }

        return singleton;
    }

    public void finalize() {
        try {
            context.getRepository().shutDown();
        } catch (RepositoryException e) {
            new SimpleException(e).logError();
        }

        context.close();
    }

    public StarGazerContext getContext() {
        return context;
    }

    private StarGazer() throws SimpleException {
        Repository repo = new SailRepository(
                new ForwardChainingRDFSInferencer(
                        new MemoryStore()));
        try {
            repo.initialize();
        } catch (RepositoryException e) {
            throw new SimpleException(e);
        }
        try {
            RepositoryConnection rc = repo.getConnection();
            rc.setNamespace("rdf", RDF.NAMESPACE);
            rc.setNamespace("sg", NS);
            
            try {
                rc.add(StarGazer.class.getResourceAsStream("stargazer.owl"), BASE_URI, RDFFormat.RDFXML);
            } catch (IOException e) {
                throw new SimpleException(e);
            } catch (RDFParseException e) {
                throw new SimpleException(e);
            } finally {
                rc.close();
            }
        } catch (RepositoryException e) {
            throw new SimpleException(e);
        }

        context = new StarGazerContext(repo);
    }

    private static String qNameToString(final QName qname) {
        return qname.getNamespaceURI() + qname.getLocalPart();
    }

    public static Map<String, String> getByName(String name) throws Exception {
        StarGazerContext ctx = getInstance().getContext();

        Map<String, String> thisStar = new HashMap<String, String>();

//                Collection<Star> allStars = ctx.getAllStars();
        Star star = Math.getStarDetailsByName(ctx.getRepository(), name);

        thisStar.put("URI", qNameToString(star.getQName()));
        if (null != star.getHasName())
            thisStar.put("NAME", star.getHasName().toString());
        if (null != star.getHasMessierNumber())
            thisStar.put("MESSIER_NUMBER", star.getHasMessierNumber().toString());
        if (null != star.getHasNGCNumber())
            thisStar.put("NGC_NUMBER", star.getHasNGCNumber().toString());
        if (null != star.getHasRightAscension())
            thisStar.put("RIGHT_ASCENSION", star.getHasRightAscension().toString());
        if (null != star.getHasDeclination())
            thisStar.put("DECLINATION", star.getHasDeclination().toString());
        if (null != star.getHasAbsoluteMagnitude())
            thisStar.put("ABSOLUTE_MAGNITUDE", star.getHasAbsoluteMagnitude().toString());
        if (null != star.getHasApparentMagnitude())
            thisStar.put("APPARENT_MAGNITUDE", star.getHasApparentMagnitude().toString());
        if (null != star.getHasLuminosity())
            thisStar.put("LUMINOSITY", star.getHasLuminosity().toString());
        if (null != star.getHasSolarMasses())
            thisStar.put("SOLAR_MASSES", star.getHasSolarMasses().toString());
        if (null != star.getHasMeanSolarRadius())
            thisStar.put("MEAN_SOLAR_RADIUS", star.getHasMeanSolarRadius().toString());
        if (null != star.getHasMetallicity())
            thisStar.put("METALLICITY", star.getHasMetallicity().toString());
        if (null != star.getHasSpectralType())
            thisStar.put("SPECTRAL_TYPE", star.getHasSpectralType().getRdfsLabel().toString());

        return thisStar;
    }


    public static Collection<Map<String, String>> get(String[] UserCoordinates, String[] SkyCoordinates, String[] TimeInformation) throws Exception {
        StarGazerContext ctx = getInstance().getContext();

        Collection<Map<String, String>> retStars = new HashSet<Map<String, String>>();

        System.out.println("ON SERVER: ");
        System.out.println(UserCoordinates[0]);
        System.out.println(SkyCoordinates[0]);
        System.out.println(TimeInformation[0]);

        /*	Location curLocation = new Location(Double.valueOf(UserCoordinates[0]).doubleValue(), Double.valueOf(UserCoordinates[1]).doubleValue());
          Position curPos1 = new Position(SkyCoordinates[0], SkyCoordinates[2]);
          Position curPos2 = new Position(SkyCoordinates[1], SkyCoordinates[3]);
          SkyRegion skyRegion = new SkyRegion(curPos1, curPos2);

          Time curTime = new Time(TimeInformation[0],TimeInformation[1],TimeInformation[2],
                          TimeInformation[3],TimeInformation[4],TimeInformation[5]);
          */
        System.out.println("ON SERVER (1a) ");
        System.out.println("ON SERVER (1b) ");
        Collection<Star> allStars = ctx.getAllStars();

//                Collection<Star> allStars = Math.getStarsWithinLocation(repo, curLocation, curTime, skyRegion);
        System.out.println("ON SERVER (2) ");
        int i = 0;
        for (Star star : allStars) {
            Map<String, String> thisStar = new HashMap<String, String>();

            thisStar.put("URI", qNameToString(star.getQName()));
            if (null != star.getHasName())
                thisStar.put("NAME", star.getHasName().toString());
            if (null != star.getHasMessierNumber())
                thisStar.put("MESSIER_NUMBER", star.getHasMessierNumber().toString());
            if (null != star.getHasNGCNumber())
                thisStar.put("NGC_NUMBER", star.getHasNGCNumber().toString());
            if (null != star.getHasRightAscension())
                thisStar.put("RIGHT_ASCENSION", star.getHasRightAscension().toString());
            if (null != star.getHasDeclination())
                thisStar.put("DECLINATION", star.getHasDeclination().toString());
            if (null != star.getHasAbsoluteMagnitude())
                thisStar.put("ABSOLUTE_MAGNITUDE", star.getHasAbsoluteMagnitude().toString());
            if (null != star.getHasApparentMagnitude())
                thisStar.put("APPARENT_MAGNITUDE", star.getHasApparentMagnitude().toString());
            if (null != star.getHasLuminosity())
                thisStar.put("LUMINOSITY", star.getHasLuminosity().toString());
            if (null != star.getHasSolarMasses())
                thisStar.put("SOLAR_MASSES", star.getHasSolarMasses().toString());
            if (null != star.getHasMeanSolarRadius())
                thisStar.put("MEAN_SOLAR_RADIUS", star.getHasMeanSolarRadius().toString());
            if (null != star.getHasMetallicity())
                thisStar.put("METALLICITY", star.getHasMetallicity().toString());
            if (null != star.getHasSpectralType())
                thisStar.put("SPECTRAL_TYPE", star.getHasSpectralType().getRdfsLabel().toString());
            retStars.add(thisStar);
        }

        return retStars;
    }
}
